<template>
  <div style="height: 100%; overflow: auto; padding: 20px">
    <fm-generate-form
      :data="JSON.parse(controlData.designData)"
      :remote="remoteFuncs"
      v-model="models"
      :pageAction="pageAction"
      ref="smartform"
      :objectKey="objectKey"
      v-if="!pageLoading"
      @loaded="loadDone"
    >
      <template v-slot:inner>
        <div v-html="vHtml"></div>
      </template>
    </fm-generate-form>

    <iframe ref="smartform_jsframe" name="smartform_jsframe" v-show="false"></iframe>
  </div>
</template>

<script>
import controller from "@/libs/framework/controller";
import _ from "lodash";
import Injection from "@/libs/framework/injection";
import LoaderProxy from "@/libs/framework/loaderProxy";
import user from "@/store/modules/user";
import { smartformDB, queryOne, del, add } from "@/utils/dexie.js";

export default class instance extends controller {
  onBeforeInit() {
    this.urls = {
      model: "/smartform/mobile/hub/",
      save: "/smartform/save",
    };
  }

  onInit() {
    let pageId = this.vm.pageId;
    let pageCode = this.vm.pageCode || this.$params.pageCode;
    let version = this.vm.version;
    let pkey = this.vm.pkey;

    let url = `/smartform/mobile/hub/${pageCode}`;
    this.urls.model = url;

    if (pageId) {
      this.setRequestParam("pageId", pageId, "form");
    }
    if (version) {
      this.setRequestParam("version", version, "form");
    }
    if (pkey) {
      _.each(pkey, (v, k) => {
        this.setRequestParam(k, v, "form");
      });
    }
  }

  async getViewModel(conditions, preloader = false) {
    let pageCode = this.vm.pageCode || this.$params.pageCode;
    this.context.pageLoading = true;
    let loading;
    if (preloader) {
      loading = this.vm.appLoading("数据加载中...");
    }

    /**
     * 部分数据由前端进行缓存(cssCode、designData、jsCode、watchProp)
     * 以hasFrontEndCache用于区分是否需要查询缓存数据
     */
    // cacheKey为userId&pageCode
    const isCache = process.env.VUE_APP_SMARTFORM_CACHE === true;
    if (isCache) {
      const cacheKey = user.state.userId + "&" + pageCode;
      const cacheData = await queryOne(
        smartformDB,
        "smartformCacheTable",
        "cacheKey",
        cacheKey
      );
      if (!cacheData) {
        this.setRequestParam("hasFrontEndCache", false, "form");
      } else {
        const { cacheCreateTime } = cacheData;
        // cacheCreateTime无效，或者已过期
        if (
          cacheCreateTime == null ||
          parseInt(
            (new Date().getTime() - cacheCreateTime) / 1000 / (60 * 60)
          ) > 24
        ) {
          this.setRequestParam("hasFrontEndCache", false, "form");
          await del(smartformDB, "smartformCacheTable", "cacheKey", cacheKey);
        } else {
          this.setRequestParam("hasFrontEndCache", true, "form");
        }
      }
    } else {
      this.setRequestParam("hasFrontEndCache", false, "form");
    }
    return new Promise((resolve, reject) => {
      new LoaderProxy(this, conditions).load(resolve, reject, preloader);
    })
      .then(() => {
        this.context.pageLoading = false;
        if (preloader) {
          loading.close();
        }
      })
      .catch(() => {
        this.context.pageLoading = false;
        if (preloader) {
          loading.close();
        }
      });
  }

  async onAfterQuery(type, isSuccess, result) {
    if (isSuccess) {
      // if (result.enums) {
      //   this.vm.$root.enums = result.enums;
      // }
      // if (result.dicts) {
      //   this.vm.$root.dicts = result.dicts;
      // }
      // if (result.controlData) {
      //   this.vm.$root.controlData = result.controlData;
      // }
      if (result.models && result.models.model) {
        let datakey = result.models.model["datakey"];
        result.models.model["datakey"] = datakey || Math.uuid();
      }

      const isCache = process.env.VUE_APP_SMARTFORM_CACHE === true;
      if (isCache) {
        const { cssCode, designData, jsCode, watchProp } = result.controlData;
        const { formCode } = result.models.model;
        // cacheKey为userId&formCode
        const cacheKey = user.state.userId + "&" + formCode;
        const cacheData = await queryOne(
          smartformDB,
          "smartformCacheTable",
          "cacheKey",
          cacheKey
        );
        if (cacheData) {
          const { cssCode, designData, jsCode, watchProp } = cacheData;
          Object.assign(result.controlData, {
            cssCode: cssCode,
            designData: designData,
            jsCode: jsCode,
            watchProp: watchProp,
          });
        } else {
          await add(smartformDB, "smartformCacheTable", {
            cacheKey: cacheKey,
            cacheCreateTime: new Date(),
            cssCode: cssCode,
            designData: designData,
            jsCode: jsCode,
            watchProp: watchProp,
          });
        }
      }
    }

    this.vm.loadJs(result);
    this.vm.loadVueMethod(result);

    return result;
  }

  mixin() {
    return {
      props: {
        // 表单相关
        pageId: String,
        pageCode: String,
        version: String | Number,
        // 工作流相关
        appCode: String,
        taskId: String,
        historyTaskId: String,
        assigneeId: String,
        // 主键
        pkey: Object,
      },
      data() {
        return {
          pageLoading: false,
          controlData: {
            formTables: [],
            tableColumns: [],
            tables: [],
            designData: `{
              "list": [],
              "f7list": [],
              "config": {
                "labelWidth": 100,
                "labelPosition": "right",
                "size": "small",
                "customClass": "",
                "ui": "element",
                "layout": "horizontal",
                "labelCol": 3
              },
              "page": {
                "pageId": "",
                "title": "",
                "onVueCreated": "",
                "onVueMounted": ""
              },
              "f7page": {
                "pageContent": true,
                "hideNavbarOnScroll": false,
                "hideToolbarOnScroll": false,
                "ptr": true,
                "infinite": true,
                "onVueCreated": "",
                "onVueMounted": ""
              }
            }`,
          },
          primaryKey: {},
          pageAction: "create",
          jsonData: {},
          editData: {},
          remoteFuncs: {},
          formName: "smartform",
          enums: {},
          dicts: {},
          models: {
            model: {},
          },
          vHtml: "",
          objectKey: "",
          isSaved: false,
        };
      },
      methods: {
        getData() {
          return this.$refs.smartform.getData();
        },
        saveThenReload() {
          let self = this;
          // 只有最初一次新增时保存之后才重新加载数据
          if (self.pageAction != "create") {
            return;
          }
          let loading = self.notifyInfo("数据加载中");
          let storeId = self.models.model.storeId;
          let pageCode = self.models.model.formCode;

          let url = `/smartform/mobile/edit/${pageCode}`;
          self.super.urls.model = url;

          self.getViewModel({ storeId: storeId }).then(() => {
            loading.close();
          });
        },
        loadVueMethod(result) {
          let vueMethod = {};
          let frameWindow = this.$refs.smartform_jsframe.contentWindow;

          if (
            result &&
            result.controlData &&
            result.controlData.vueMethod &&
            frameWindow
          ) {
            let vMetText = result.controlData.vueMethod;
            if (!vMetText.startsWith("{")) {
              vMetText = "{" + vMetText + "}";
            }

            vueMethod = JSON.stringify(vMetText, function (key, val) {
              if (typeof val === "function") {
                return val + "";
              }
              return val;
            });
            vueMethod = JSON.parse(vueMethod, function (k, v) {
              if (v.indexOf && v.indexOf("function") > -1) {
                return frameWindow.eval("(function(){return " + v + " })()");
              }
              return v;
            });
          }

          _.each(vueMethod, (value, key) => {
            if (typeof value === "function") {
              this[key] = function () {
                return value(...arguments);
              };
            }
          });
        },
        loadJs(result) {
          result = result || { controlData: {} };
          // 该 htmlClear 方法有问题，希望开发人员写的js不要有XSS风险
          // let js = this.super.$util.htmlClear(result.controlData.jsCode || "");
          let js = result.controlData.jsCode || "";
          let frameWindow = this.$refs.smartform_jsframe.contentWindow;
          if (frameWindow) {
            frameWindow.vue = this;
            frameWindow.data = result;
            Injection.injectSmartformJs(frameWindow);

            const s = frameWindow.document.createElement("script");
            s.type = "text/javascript";
            s.innerHTML = `${js}`;
            frameWindow.document.body.appendChild(s);
          }

          this.objectKey = Math.uuid();
          window[this.objectKey] = frameWindow;
        },
        loadCss() {
          let h = this.super.$util.htmlClear(this.controlData.cssCode || "");
          this.vHtml = `<style> ${h} </style>`;
        },
        loadWatchProp() {
          let watchProp = {};
          let frameWindow = this.$refs.smartform_jsframe.contentWindow;

          if (this.controlData.watchProp && frameWindow) {
            let wpText = this.controlData.watchProp;
            if (!wpText.startsWith("{")) {
              wpText = "{" + wpText + "}";
            }

            watchProp = JSON.stringify(wpText, function (key, val) {
              if (typeof val === "function") {
                return val + "";
              }
              return val;
            });

            watchProp = JSON.parse(watchProp, function (k, v) {
              if (v.indexOf && v.indexOf("function") > -1) {
                return frameWindow.eval("(function(){return " + v + " })()");
              }
              return v;
            });
          }

          let self = this;

          _.each(watchProp, (value, key) => {
            this.$watch(key, function (newVal, oldVal) {
              if (typeof value === "function") {
                value(newVal, oldVal, self);
              }
            });
          });
        },
        loadDone() {
          this.loadCss();
          this.loadWatchProp();

          let $smartform = this.$refs["smartform"];
          // if (
          //   $smartform.data.page.onVueCreated &&
          //   this[$smartform.data.page.onVueCreated]
          // ) {
          //   this[$smartform.data.page.onVueCreated](
          //     $smartform.$refs["elementGenerateForm"]
          //   );
          // }

          // if (
          //   $smartform.data.page.onVueMounted &&
          //   this[$smartform.data.page.onVueMounted]
          // ) {
          //   this[$smartform.data.page.onVueMounted](
          //     $smartform.$refs["elementGenerateForm"]
          //   );
          // }

          if (this.pageAction === "view") {
            $smartform.disabled("all", true);
          }
        },

        getModels() {
          return this.$refs.smartform.models;
        },

        appendPrimaryKey(url, model) {
          if (!model) return url;
          for (let o in model) {
            let joinChar = url.indexOf("?") == -1 ? "?" : "&";
            url += joinChar;
            url += o + "=" + encodeURI(model[o] || "");
          }
          return url;
        },

        close() {
          this.$root.closeModal(null, this.isSaved);
        },

        save() {
          this.$refs.smartform
            .getData()
            .then((d) => {
              let postModel = this.models;
              postModel.pageAction = this.pageAction;
              let url = this.appendPrimaryKey(this.urls.save, this.primaryKey);
              if (
                this.onBeforeSave &&
                this.onBeforeSave(postModel, url) === false
              ) {
                return;
              }
              const loading = this.$loading({
                lock: true,
                text: "正在保存中",
              });
              this.$http
                .post(url, postModel)
                .then((rlt) => {
                  loading.close();
                  if (
                    this.onAfterSave &&
                    this.onAfterSave(rlt, postModel) !== true
                  ) {
                    return;
                  }
                  if (rlt && rlt.success) {
                    this.$message({
                      type: "success",
                      message: rlt.message || "保存成功！",
                      onClose: () => {
                        this.saveThenReload();
                      },
                    });
                    this.isSaved = true;
                  } else {
                    rlt = rlt || {};
                    this.$message({
                      type: "error",
                      message: rlt.message || "保存失败！",
                    });
                  }
                })
                .catch(function (e) {
                  this.$message({ type: "error", message: "保存失败！" });
                  loading.close();
                });
            })
            .catch((e) => {
              this.$message({ type: "error", message: "表单校验未通过！" });
              return false;
            });
        },
      },

      mounted() {
        this.$once("hook:beforeDestroy", () => {
          if (this.objectKey) {
            window[this.objectKey] = null;
          }
        });
      },
      activated() {
        this.loadJs(this.$data);
        this.loadVueMethod(this.$data);
      },
    };
  }
}
</script>

<style scoped>
</style>
